using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;


namespace Dungeon_Dive
{
    public enum TileTypes { Wall, Floor, Portal,
                            Earthportal, Waterportal, Airportal, Fireportal }

    // This class isn't very reuseable.
    // In principle should make a general base class for tiles and derive a class for DD tiles.   
    // Really, should rethink and rewrite the whole thing.

    /// <summary>
    /// This is a game component representing 3D tiles.
    /// </summary>
    public class TriDTile : Microsoft.Xna.Framework.DrawableGameComponent
    {       
        static string[] modelNames;
        static Model[] tileModels;

        static TriDTile () 
        { // static initializations

            modelNames = new string[7];
            tileModels = new Model[7];            

            modelNames[(int)TileTypes.Wall] = "Models\\wall2";
            modelNames[(int)TileTypes.Floor] = "Models\\floor2";
            modelNames[(int)TileTypes.Portal] = "Models\\portalnormal";
            modelNames[(int)TileTypes.Earthportal] = "Models\\portalearth";
            modelNames[(int)TileTypes.Waterportal] = "Models\\portalwater";
            modelNames[(int)TileTypes.Airportal] = "Models\\portalair";
            modelNames[(int)TileTypes.Fireportal] = "Models\\portalfire";
        }

        Game parentGame;

        public Model Model
        {
            get
            {
                return tileModels[(int)Type];                
            }
        }

        public TileTypes Type { get; private set; }

        public Vector3 Position{ get; set;}

        public Matrix World
        {
            get { return worldRotation * worldTranslation; }
        }

        public BoundingBox BoundingBox { get; private set; }        

        Matrix worldRotation;
        Matrix worldTranslation;

        public TriDTile(Game game, Vector3 pos, TileTypes type)
            : base(game)
        {
            parentGame = game;
            Position = pos;

            for (int i = 0; i<7; ++i)
            {
                if (tileModels[i] == null)
                    tileModels[i] = parentGame.Content.Load<Model>(modelNames[i]);
            }

            Type = type;

            worldRotation = Matrix.Identity;
            worldTranslation = Matrix.Identity * Matrix.CreateTranslation(Position);

            BoundingBox = GetBoundingBox();
        }

        /// <summary>
        /// Allows the game component to perform any initialization it needs to before starting
        /// to run.  This is where it can query for any required services and load content.
        /// </summary>
        public override void Initialize()
        {
            base.Initialize();
        }

        protected override void LoadContent()
        {            
            base.LoadContent();
        }

        /// <summary>
        /// Allows the game component to update itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        public override void Update(GameTime gameTime)
        {
            base.Update(gameTime);
        }

        public override void Draw(GameTime gameTime)
        {
            base.Draw(gameTime);
        }

        private BoundingBox GetBoundingBox()    // this is a little clumsy
        {
            BoundingBox iBox;
            List<Vector3> corners = new List<Vector3>();            

            foreach (ModelMesh mesh in Model.Meshes)
            {
                iBox = new BoundingBox();
                BorrowedTools.CalculateBoundingBox(mesh, out iBox);
                corners.AddRange(iBox.GetCorners());
            }

            BoundingBox bb = BoundingBox.CreateFromPoints(corners);

            Vector3[] ta = new Vector3[2]{bb.Max,bb.Min};            

            ta[0] += Position;
            ta[1] += Position;

            BoundingBox tb = BoundingBox.CreateFromPoints(ta);

            return tb;
        }
    }
}